package com.radar.io;

import cn.hutool.core.exceptions.UtilException;
import cn.hutool.core.io.FastByteArrayOutputStream;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.ZipUtil;
import com.radar.common.CinradType;
import com.radar.common.FileType;
import com.radar.exception.RadarDecodeError;
import org.python.apache.commons.compress.compressors.bzip2.BZip2CompressorInputStream;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.Date;
import java.util.Enumeration;
import java.util.zip.GZIPInputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

/**
 * @author: fy-wbj
 * @description: Radar basics class
 * @date: 2020/9/17
 */
public abstract class BaseRadr {

    /**
     * radar file bytes
     */
    public byte[] bytes;

    /**
     * radar station num
     */
    public String code = null;

    /**
     * CinradRadar type
     */
    public CinradType type = null;

    public FileType datType = FileType.CINRAD;

    /**
     * longitude
     */
    public double lon;

    /**
     * latitude
     */
    public double lat;

    /**
     * Station height
     */
    public double alt;

    /**
     * Observation time
     */
    public Date date;

    private static byte[] ZIP_HEADER_1 = new byte[] { 80, 75, 3, 4 };

    private static byte[] ZIP_HEADER_2 = new byte[] { 80, 75, 5, 6 };

    /**
     * Parse radar files
     *
     * @param file file path
     * @throws RadarDecodeError
     */
    public void parse(String file) throws RadarDecodeError {
        if (!FileUtil.isFile(file) && new File(file).length() > 3) {
            throw new RadarDecodeError("radar file is not found | file length < 3");
        }
        byte[] bytes = FileUtil.readBytes(file);
        int magic = bytes[0] & 0xff | ((bytes[1] << 8) & 0xff00);
        int magic1 = (bytes[1] & 0xFF)<<8 | bytes[0];
        if (magic == GZIPInputStream.GZIP_MAGIC || (magic1 == GZIPInputStream.GZIP_MAGIC)) {
            // gzip compress
            this.bytes = ZipUtil.unGzip(bytes);
            return;
        }
        String h = new String(new byte[]{bytes[0], bytes[1], bytes[2]});
        if (h.equals("BZh")) {
            // bz2 compress
            this.bytes = decompressBZ2(bytes);
            return;
        }
        byte[] buffer = new byte[4];
        buffer[0] = bytes[0];
        buffer[1] = bytes[1];
        buffer[2] = bytes[2];
        buffer[3] = bytes[3];
        if((Arrays.equals(ZIP_HEADER_1, buffer)) || (Arrays.equals(ZIP_HEADER_2, buffer))){
            // zip compress
            this.bytes = unzipFileBytes(new File(file),Charset.defaultCharset());
            return;
        }
        this.bytes = bytes;
    }

    /**
     * Decompress bz2 Compressed file
     *
     * @param bytes
     * @return
     * @throws RadarDecodeError
     */
    public static byte[] decompressBZ2(byte[] bytes) throws RadarDecodeError {
        try (ByteArrayInputStream fis = new ByteArrayInputStream(bytes);
             BZip2CompressorInputStream bis = new BZip2CompressorInputStream(fis);
             FastByteArrayOutputStream fastByteArrayOutputStream = new FastByteArrayOutputStream(bytes.length)) {
            int count;
            byte data[] = new byte[2048];
            while ((count = bis.read(data)) != -1) {
                fastByteArrayOutputStream.write(data, 0, count);
            }
            fastByteArrayOutputStream.flush();
            return fastByteArrayOutputStream.toByteArray();
        } catch (Exception e) {
            throw new RadarDecodeError("decompressBZ2 failed");
        }
    }

    public abstract void dispose();

    private static byte[] unzipFileBytes(File zipFile, Charset charset) {
        ZipFile zipFileObj = null;

        try {
            zipFileObj = new ZipFile(zipFile, charset);
            Enumeration<ZipEntry> em = (Enumeration<ZipEntry>) zipFileObj.entries();
            ZipEntry zipEntry = null;

            while(em.hasMoreElements()) {
                zipEntry = (ZipEntry)em.nextElement();
                if (!zipEntry.isDirectory()) {
                    byte[] var6 = IoUtil.readBytes(zipFileObj.getInputStream(zipEntry));
                    return var6;
                }
            }
        } catch (IOException var10) {
            throw new UtilException(var10);
        } finally {
            IoUtil.close(zipFileObj);
        }

        return null;
    }

//    public static void main(String[] args) {
//        System.out.println("开始单次三维组网拼图 args: {} ");
//        System.out.println("开始检索范围 time range : 6 minute 内雷达数据");
//        System.out.println("success ----------- ");
//        System.out.println("files length : 6");
//        System.out.println("start process -----------");
//        System.out.println("参与三维组网 : 20201001.000000.Z9871.zip , 20201001.000000.Z9883.zip, 20201001.000000.Z9888.zip, 20201001.000200.Z9692.zip, 20201001.000200.Z9874.zip, 20201001.000200.Z9876.zip");
//        System.out.println("Projection 20201001.000000.Z9871.zip interpolation 3D sucess time : 3578 s");
//        System.out.println("Projection 20201001.000000.Z9883.zip interpolation 3D sucess time : 2061 s");
//        System.out.println("Projection 20201001.000000.Z9888.zip interpolation 3D sucess time : 6831 s");
//        System.out.println("Projection 20201001.000200.Z9692.zip interpolation 3D sucess time : 4502 s");
//        System.out.println("Projection 20201001.000200.Z9874.zip interpolation 3D sucess time : 3849 s");
//        System.out.println("Projection 20201001.000200.Z9876.zip interpolation 3D sucess time : 3810 s");
//        System.out.println("MOSAIC RADAR INTERPOLATION 3D -------------");
//        System.out.println("MOSAIC RADAR INTERPOLATION 3D success");
//        System.out.println("WRITE NC PRODUCT FILE");
//    }

}

